/**
 <!-- &#64; is code of the @ 'at' sign -->
 <!-- #6f99bf is color for highlighting headers -->
 <!-- &raquo; is right quote symbol -->
 <style>
 h5 {
    color: #6f99bf;
 }
 </style>

 <h3><font color="Magenta">&raquo;&raquo;&raquo;</font> Entry point to the Multitester library.</h3>
 <h5>Introduction</h5>
 Multitester was developed for certain purpose: writing common test cases for multiple implementations of particular
 methods.
 <p>
 It means that it well suited in situations when there are multiple implementations of a single interface. Methods
 which are declared in the interface should have the same behaviour in all implementations. But each implementation requires
 specific initialization before it can be used. Lets consider the following example:<br>&nbsp;<br>
 <img src="doc-files/example_class_diagram.jpeg"/>
 <p>
 File-based implementation of storage engine creates some subsidiary files. Cloud-based implementation requires network connection.

 <h5>Our approach to writing unit test for multiple implementations</h5>

 First of all we should ensure that each instance of tested class can be initialized correctly by appropriate methods
 (<code>lockDirectory()</code> and <code>connect()</code> correspondingly). Ok, we have test cases for these methods already
 (also some shutting down methods should be presented but we omit them for clarity). Then we write test cases
 for <code>store()</code> method of <code>FileStorage</code> implementation. 
 And it becomes obvious that significant part of this test code is actual for <code>CloudStorage</code>'s test cases.
 The differences are only in starting-up and shutting-down actions.
 <p>
 Perhaps, we use some testing framework like <strong>JUnit</strong> or <strong>TestNG</strong>. Our test cases are formed as Java classes.
 It can be not appropriate for concrete situations (each developer can devised his own structure of test classes) but our
 tests have defined structure. All tests for each implementation are placed into package with name equal to the class name.
 For <code>FileStorage</code> it will be <code>FileStorage</code>. Test classes are located in that package.
 Each test class corresponds to the separate method.
 Its name is made up from tested class name, underscore, tested method name and 'Test' suffix.
 For <code>FileStorage</code> class the structure described about will look like the following:
 
  <pre>
 "root package" +
                |
                +-FileStorage-+
                |             |
                |             +-FileStorage_lockDirectoryTest.java
                |             +-FileStorage_storeTest.java
                |               ...
                ...
 </pre>

 It is obvious that in FileStorage_storeTest we have code for locking directory. Most likely that such code are factored
 into separate method. This method doesn't take parameters and doesn't returns a value. Lets it looks like
 <code>protected void init() {...}</code>.
 Also we have instance of the class which is under test. Something like <code>protected FileStorage storage</code>.

 <h5>Test classes for each implementation</h5>

 Lets test classes for example above look like the following:
 <p>
 <pre>
 public class FileStorage_storeTest {

    protected FileStorage storage;

    &#64;Before
    protected init() {
        storage = new FileStorage();
        storage.lockDirectory("testdir);
    }

    &#64;Test
    public void dataIsNull() {
        try {
            storage.store(null);
        } catch (Exception ex) {
            assertEquals(ex.getClass(), IllegalArgumentException.class);
        }
    }

    &#64;Test
    public void storeOneByte() {
        int id = storage.store(new ByteArray(0));
        ByteArray stored = storage.get(id).
        assertEquals(new ByteArray(0), stored);
    }

    &#64;Test
    public void storeTwoBytes() {
        int id = storage.store(new ByteArray(1, 2));
        ByteArray stored = storage.get(id).
        assertEquals(new ByteArray(1, 2), stored);
    }

    &#64;Test
    public void diskErrorArise() {
        FileSystemUtils.unlock("testdir");
        FileSystemUtils.remove("testdir");
        try {
            storage.store(new ByteArray(0));
        } catch (Exception ex) {
            assertEquals(ex.getClass(), IllegalStateException.class);
        }
    }

    // more test cases here

 }
 </pre>
 <p>
 And test for <code>CloudStorage.store()</code>:
 <p>
 <pre>
 public class CloudStorage_storeTest {
    
    private static final HOST = "mycloudhost.com";
    private static final LOGIN = "testaccount";
    private static final PASSWORD = "passwordfortestaccount";

    protected CloudStorage storage;

    &#64;Before
    protected init() {
        storage = new CloudStorage();
        storage.connect(HOST, LOGIN, PASSWORD);
    }

    &#64;Test
    public void dataIsNull() {
        try {
            storage.store(null);
        } catch (Exception ex) {
            assertEquals(ex.getClass(), IllegalArgumentException.class);
        }
    }

    &#64;Test
    public void storeOneByte() {
        int id = storage.store(new ByteArray(0));
        ByteArray stored = storage.get(id).
        assertEquals(new ByteArray(0), stored);
    }

    &#64;Test
    public void storeTwoBytes() {
        int id = storage.store(new ByteArray(1, 2));
        ByteArray stored = storage.get(id).
        assertEquals(new ByteArray(1, 2), stored);
    }

    &#64;Test
    public void connectionLost() {
        Network.shutdown();
        try {
           storage.store(new ByteArray(0));
        } catch (Exception ex) {
            assertEquals(ex.getClass(), IllegalStateException.class);
        }
    }

    // more test cases here

 }
 </pre>
    <p>
 It is obvious that both tests don't differ in all test methods. <code>storeOneByte</code> and <code>storeTwoBytes</code> have common behavior.
 So it will be nice to extract them into another test class. And apply the same test cases for both <code>FileStorage</code>
 and <code>CloudStorage</code> implementations.

 <h5>Parameterized tests are in action</h5>

 Common behavior can be achieved with <strong>parameterized tests</strong>. This concept is widely used in JUnit and TestNG.
 In most situations parameterized tests are well suited for providing different input data for single test case. But in our
 example the concrete implementation of <code>IStorage</code> interface will be used as parameter. And each test case will
 be run first for <code>FileStorage</code> then for <code>CloudStorage</code>.
    <p>
 Such parametrization can be achieved in different ways.
 <ul>
 <li>Static factories which provide instances of certain implementations</li>
 <li>Factoring common test case into abstract class (each subclass is test for implementation)</li>
 ...
 </ul>
    <p>
 Lets see how it can be achieved with annotations. It will take some steps.
 
 <h5>Use annotations for getting parameterized tests working</h5>
 
 <ol>
 <li>Factor all starting-up and shutting-down actions into instance methods which doesn't take parameters and doesn't
 return any value (they are named 'void-methods' here).</li>
 
 <li>Mark these methods with {@link com.google.code.multitester.annonations.Exported} annotation and provide string
 alias that is unique in whole hierarchy of test class
 (see {@link com.google.code.multitester.annonations.processors.ExportedMethodsFinder})</li>
 
 <li>Mark all fields which can be used in common test case with {@link com.google.code.multitester.annonations.Exported} 
 annotation and provide string alias that is unique in whole hierarchy. It should be unique only among marked fields
 (see {@link com.google.code.multitester.annonations.processors.ExportedFieldsFinder} for details) </li>

 <li>Create new empty public class and mark it with {@link com.google.code.multitester.annonations.ImportedTest} annotation.
 Provide name of the test class specific for certain implementation, sequence of starting-up and shutting-down methods.</li>

 <li>Write our own test class (see TestNG example here !TODO link to the page of source code instead javadoc page {@link com.google.code.multitester.integrationtests.example_of_using_multitester.IStub.IStub_sayTest}).
 In each test case add code for getting value of instance that is under test. In our example instance of the <code>IStorage</code>
 is under test.</li>
 </ol>

 For our example all job looks like this:
 <ol>
 <li>Starting-up and shutting-down actions are already factored into void-methods (shutting-down is omitted for clarity).
 Mark them as exported. Look at them:

 <ul>
 <li>
 from test for <code>FileStorage</code> implementation:<br>
 <pre>
 &#64;Before
 &#64;Exported("init")
 protected init() {
    storage = new FileStorage();
    storage.lockDirectory("testdir);
 }
 </pre>
 </li>
  
 <li>
 from test for <code>CloudStorage</code> implementation:<br>
 <pre>
 &#64;Before
 &#64;Exported("startup")
 protected init() {
    storage = new CloudStorage();
    storage.connect(HOST, LOGIN, PASSWORD);
 }
 </pre>
 </li>
 </ul>
 </li>

 <li>
 Mark <code>storage</code> fields as exported. We feel free to choose aliases but it is mandatory have different aliases
 in the hierarchy but the same alias across different implementations.
 <pre>
 &#64;Exported("storage")
 protected FileStorage storage;

 &#64;Exported("storage")
 protected CloudStorage storage;
 </pre>
 </li>

 <li>
 Create empty configuration classes for each implementation test.<br>
 <ul>
 <li><a name="FileStorage_configuration_class"/>for <code>FileStorage</code> implementation:
 <pre>
 &#64;ImportedTest(testClass=FileStorage_storeTest.class,
               startupSequence={"init"},
               shutdownSequence={})
 public class FileStorage_storeTestConfig {  }
 </pre>
 </li>
 
 <li><a name="CloudStorage_confuguration_class"/>for <code>CloudStorage</code> implementation:
 <pre>
 &#64;ImportedTest(testClass=CloudStorage_storeTest.class,
               startupSequence={"startup"},
               shutdownSequence={})
 public class CloudStorage_storeTestConfig {  }
 </pre>
 </li>
 </ul>
 </li>

 <li>Write common test cases for <code>store()</code> method.<br>
 We create one test class <code>IStorage_storeTest</code> and add parameters using TestNG's  <code>&#64;DataProvider</code> feature.
 Then we add test cases from <code>FileStorage_storeTest</code> and transform them to common test cases.</li>

 </ol>


 <h5>Look at the result</h5>

 <pre>
 public class IStorage_storeTest {

    <font color="Gray">// configuration of multiple implementation tests</font>
    <font color="DarkGoldenRod">&#64;DataProvider(name="storeTestProvider")</font>
    public Object[][] provide() throws Exception {
        return new Object[][] {
            { <a href="#FileStorage_configuration_class">FileStorage_storeTestConfig.class</a> },
            { <a href="#CloudStorage_confuguration_class">CloudStorage_storeTestConfig.class</a> }
        };
    }

    &#64;Test(dataProvider="storeTestProvider")
    public void storeOneByte(Class testCaseConfiguration) throws Exception {
        <font color="IndianRed">MultiTester tester = new MultiTester(testCaseConfiguration);</font> <font color="Grey">// multitester API goes on stage</font>
        <font color="IndianRed">tester.startup();</font> <font color="Grey">// perform all initialization methods from startup sequence</font>
        <font color="IndianRed">IStorage storage = tester.importField("storage", IStorage.class);</font> <font color="Grey">// get actual implementation of IStorage</font>

        <font color="Grey">// next three lines come from FileStorage_storeTest.storeOneByte()</font>
        int id = storage.store(new ByteArray(0));
        ByteArray stored = storage.get(id).
        assertEquals(new ByteArray(0), stored);

        <font color="DarkOliveGreen">tester.shutdown();</font> <font color="Gray">// perform all closing methods from shutdown sequence</font>
    }

    &#64;Test(dataProvider="storeTestProvider")
    public void storeTwoBytes(Class testCaseConfiguration) throws Exception {
        MultiTester tester = new MultiTester(testCaseConfiguration);
        tester.startup();
        IStorage storage = tester.importField("storage", IStorage.class);

        int id = storage.store(new ByteArray(1, 2));
        ByteArray stored = storage.get(id).
        assertEquals(new ByteArray(1, 2), stored);

        tester.shutdown();
    }
 }
 </pre>
 </li>
 
 </ol>
 Now our common test for multiple implementations is elegant, isn't it? <strong><font color="Green">;)</font></strong>

 *
 * @author Yuriy Sechko
 */
package com.google.code.multitester;

